#include "GY_GraphicsBezier.h"



GY_GraphicsBezier::GY_GraphicsBezier(const QString &guid, QGraphicsItem *parent)
    :GY_BasicsGraphicsObject(guid,this,parent)
{
    //图元类型
    GY_Object::setUserData(GY_ENUM::ClassType,QVariant("Bezier"));
    initializationPropertyInfo();
    QMap<QVariant,QPointF> editPoints = {
        {"Point1",m_PropertyInfoMap["Point1"].propertyValue.toPointF()},
        {"Ctrl1",m_PropertyInfoMap["Ctrl1"].propertyValue.toPointF()},
        {"Ctrl2",m_PropertyInfoMap["Ctrl2"].propertyValue.toPointF()},
        {"Point2",m_PropertyInfoMap["Point2"].propertyValue.toPointF()}
    };
    updateDraw();
    this->setPen(QColor(0,255,0));
    this->setEditPointF(editPoints);
}
/**
 * @brief GY_GraphicsBezier::GY_GraphicsBezier
 * @param guid
 * @param precision 精度
 * @param point1 起始点
 * @param ctrl1 起始控制点
 * @param ctrl2 结束控制点
 * @param point2 结束点
 * @param parent
 */
GY_GraphicsBezier::GY_GraphicsBezier(const QString &guid,
                                     const int precision,
                                     const QPointF point1,
                                     const QPointF ctrl1,
                                     const QPointF ctrl2,
                                     const QPointF point2,
                                     QGraphicsItem *parent)
    :GY_BasicsGraphicsObject(guid,this,parent)
{
    //图元类型
    GY_Object::setUserData(GY_ENUM::ClassType,QVariant("Bezier"));
    initializationPropertyInfo();
    QMap<QVariant,QPointF> editPoints = {
        {"Point1",m_PropertyInfoMap["Point1"].propertyValue.toPointF()},
        {"Ctrl1",m_PropertyInfoMap["Ctrl1"].propertyValue.toPointF()},
        {"Ctrl2",m_PropertyInfoMap["Ctrl2"].propertyValue.toPointF()},
        {"Point2",m_PropertyInfoMap["Point2"].propertyValue.toPointF()}
    };
    updateDraw();
    this->setPen(QColor(0,255,0));
    this->setEditPointF(editPoints);
}

GY_GraphicsBezier::~GY_GraphicsBezier()
{

}

bool GY_GraphicsBezier::updatePrecision(const QString &name, const QVariant &value)
{
    if(!value.canConvert<int>() && (value < 1 || value >100))
    {
        return false;
    }
    m_PropertyInfoMap[name].propertyValue = value;
    updateDraw();
    return true;
}

bool GY_GraphicsBezier::updatePoint1(const QString &name, const QVariant &value)
{
    if(!value.canConvert<QPointF>())
    {
        return false;
    }
    QPointF mousePoint = this->mapFromScene(value.value<QPointF>());
    m_PropertyInfoMap[name].propertyValue=mousePoint;
    QPointF point1 = m_PropertyInfoMap["Point1"].propertyValue.value<QPointF>();
    if(name.endsWith("Point1"))
    {
        point1.setX(mousePoint.x());
        point1.setY(mousePoint.y());
        m_PropertyInfoMap[name].propertyValue.toPointF();
    }
    updateDraw();
    this->setPen(QColor(0,255,0));
    this->setEditPointF(name,mousePoint);

    return true;
}

bool GY_GraphicsBezier::updateCtrl1(const QString &name, const QVariant &value)
{
    if(!value.canConvert<QPointF>())
    {
        return false;
    }
    QPointF mousePoint = this->mapFromScene(value.value<QPointF>());
    m_PropertyInfoMap[name].propertyValue=mousePoint;
    QPointF ctrl1 = m_PropertyInfoMap["Ctrl1"].propertyValue.value<QPointF>();
    if(name.endsWith("Ctrl1"))
    {
        ctrl1.setX(mousePoint.x());
        ctrl1.setY(mousePoint.y());
        m_PropertyInfoMap[name].propertyValue.toPointF();
    }
    updateDraw();
    this->setPen(QColor(0,255,0));
    this->setEditPointF(name,mousePoint);

    return true;
}

bool GY_GraphicsBezier::updateCtrl2(const QString &name, const QVariant &value)
{
    if(!value.canConvert<QPointF>())
    {
        return false;
    }
    QPointF mousePoint = this->mapFromScene(value.value<QPointF>());
    m_PropertyInfoMap[name].propertyValue=mousePoint;
    QPointF ctrl2 = m_PropertyInfoMap["Ctrl2"].propertyValue.value<QPointF>();
    if(name.endsWith("Ctrl2"))
    {
        ctrl2.setX(mousePoint.x());
        ctrl2.setY(mousePoint.y());
        m_PropertyInfoMap[name].propertyValue.toPointF();
    }
    updateDraw();
    this->setPen(QColor(0,255,0));
    this->setEditPointF(name,mousePoint);

    return true;
}

bool GY_GraphicsBezier::updatePoint2(const QString &name, const QVariant &value)
{
    if(!value.canConvert<QPointF>())
    {
        return false;
    }
    QPointF mousePoint = this->mapFromScene(value.value<QPointF>());
    m_PropertyInfoMap[name].propertyValue=mousePoint;
    QPointF point2 = m_PropertyInfoMap["Point2"].propertyValue.value<QPointF>();
    if(name.endsWith("Point2"))
    {
        point2.setX(mousePoint.x());
        point2.setY(mousePoint.y());
        m_PropertyInfoMap[name].propertyValue.toPointF();
    }
    updateDraw();
    this->setPen(QColor(0,255,0));
    this->setEditPointF(name,mousePoint);

    return true;
}

void GY_GraphicsBezier::updatePath(const QPointF &startPoint, const QPointF &endPoint,
                                   const QPointF &startCtrlPoint, const QPointF &endCtrlPoint,int precision)
{
    //绘制路径
    QPainterPath path;
    path.moveTo(startPoint);
//    qDebug()<<"precision ="<<precision;
//    path.quadTo(endCtrlPoint.x(),endCtrlPoint.y(),endPoint.x(),endPoint.y());//二阶贝塞尔曲线

    //默认精度下的三阶贝塞尔曲线
//    path.cubicTo(startCtrlPoint,endCtrlPoint,endPoint);
    path.cubicTo(startCtrlPoint.x(),startCtrlPoint.y(),
                 endCtrlPoint.x(),endCtrlPoint.y(),
                 endPoint.x(),endPoint.y());
    //通过传入的精度值precision控制贝塞尔曲线的精度，precision用于将贝塞尔曲线分段
//    for(int i=0;i<precision;i++)
//    {
//        path.cubicTo(startCtrlPoint.x()/precision,startCtrlPoint.y()/precision,
//                     endCtrlPoint.x()/precision,endCtrlPoint.y()/precision,
//                     endPoint.x(),endPoint.y());
//    }

    this->setPath(path);
}

void GY_GraphicsBezier::updateDraw()
{
    //获取存储属性信息
    QPointF point1=m_PropertyInfoMap.value("Point1").propertyValue.toPointF();
    QPointF point2=m_PropertyInfoMap.value("Point2").propertyValue.toPointF();
    QPointF ctrl1 = m_PropertyInfoMap.value("Ctrl1").propertyValue.toPointF();
    QPointF ctrl2 = m_PropertyInfoMap.value("Ctrl2").propertyValue.toPointF();
    qreal precision = m_PropertyInfoMap.value("Precision").propertyValue.value<qreal>();
    //定义绘制参数
    QPointF startPoint=point1;
    QPointF endPoint=point2;
    QPointF startCtrlPoint=ctrl1;
    QPointF endCtrlPoint=ctrl2;

    updatePath(startPoint,endPoint,startCtrlPoint,endCtrlPoint,precision);
}

void GY_GraphicsBezier::initializationPropertyInfo()
{
    GY_PropertyInfo ObjectName(this);
    ObjectName.propertyName = "ObjectName";
    ObjectName.propertyValue = QString();
    ObjectName.updateType = Update|OrdinaryAttributes;
    ObjectName.propertyType = QStringPropertyType;
    ObjectName.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsBezier::updateObjectName;
    m_PropertyInfoMap.insert("ObjectName",ObjectName);
    m_PropertyInfoMap["ObjectName"].setConnect();

    GY_PropertyInfo IsVisible(this);
    IsVisible.propertyName = "IsVisible";
    IsVisible.propertyValue = true;
    IsVisible.updateType = Update|OrdinaryAttributes;
    IsVisible.propertyType = BoolPropertyType;
    IsVisible.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsBezier::updateIsVisible;
    m_PropertyInfoMap.insert("IsVisible",IsVisible);
    m_PropertyInfoMap["IsVisible"].setConnect();

    GY_PropertyInfo IsOutLined(this);
    IsOutLined.propertyName = "IsOutlined";
    IsOutLined.propertyValue = true;
    IsOutLined.updateType = Update|OrdinaryAttributes;
    IsOutLined.propertyType = BoolPropertyType;
    IsOutLined.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsBezier::updateIsOutLined;
    m_PropertyInfoMap.insert("IsOutlined",IsOutLined);
    m_PropertyInfoMap["IsOutlined"].setConnect();

    GY_PropertyInfo IsFilled(this);
    IsFilled.propertyName = "IsFilled";
    IsFilled.propertyValue = true;
    IsFilled.updateType = Update|OrdinaryAttributes;
    IsFilled.propertyType = BoolPropertyType;
    IsFilled.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsBezier::updateIsFilled;
    m_PropertyInfoMap.insert("IsFilled",IsFilled);
    m_PropertyInfoMap["IsFilled"].setConnect();

    GY_PropertyInfo IsAntialiased(this);
    IsAntialiased.propertyName = "IsAntialiased";
    IsAntialiased.propertyValue = true;
    IsAntialiased.updateType = Update|OrdinaryAttributes;
    IsAntialiased.propertyType = BoolPropertyType;
    IsAntialiased.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsBezier::updateIsAntialiased;
    m_PropertyInfoMap.insert("IsAntialiased",IsAntialiased);
    m_PropertyInfoMap["IsAntialiased"].setConnect();

    GY_PropertyInfo PenAttributes(this);
    PenAttributes.propertyName = "PenAttributes";
    PenAttributes.propertyValue = false;
    PenAttributes.updateType = Update|OrdinaryAttributes;
    PenAttributes.propertyType = BoolPropertyType;
    PenAttributes.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsBezier::updatePenAttributes;
    m_PropertyInfoMap.insert("PenAttributes",PenAttributes);
    m_PropertyInfoMap["PenAttributes"].setConnect();

    GY_PropertyInfo PenOpacity(this);
    PenOpacity.propertyName = "PenOpacity";
    PenOpacity.propertyValue = qreal(1);
    PenOpacity.updateType = Update|OrdinaryAttributes;
    PenOpacity.propertyType = QrealPropertyType;
    PenOpacity.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsBezier::updatePenOpacity;
    m_PropertyInfoMap.insert("PenOpacity",PenOpacity);
    m_PropertyInfoMap["PenOpacity"].setConnect();

    GY_PropertyInfo LineStyle(this);
    LineStyle.propertyName = "LineStyle";
    QVector<qreal> varStyle;
    int style = Qt::SquareCap|Qt::BevelJoin|Qt::CustomDashLine;
    varStyle<<style<<2<<3<<2<<4<<5<<6<<7;
    LineStyle.propertyValue = QVariant::fromValue(varStyle);
    LineStyle.updateType = Update|OrdinaryAttributes;
    LineStyle.propertyType = LineStylePropertyType;
    LineStyle.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsBezier::updateLineStyle;
    m_PropertyInfoMap.insert("LineStyle",LineStyle);
    m_PropertyInfoMap["LineStyle"].setConnect();

    GY_PropertyInfo precision(this);
    precision.propertyName = "Precision";
    precision.propertyValue = int(20);
    precision.updateType = Update|OrdinaryAttributes;
    precision.propertyType = IntPropertyType;
    precision.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsBezier::updatePrecision;
    m_PropertyInfoMap.insert("Precision",precision);
    m_PropertyInfoMap["Precision"].setConnect();

    GY_PropertyInfo point1(this);
    point1.propertyName = "Point1";
    point1.propertyValue = QPointF(0,0);
    point1.updateType = Update|PointOfRelative;
    point1.propertyType = PointPropertyType;
    point1.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsBezier::updatePoint1;
    m_PropertyInfoMap.insert("Point1",point1);
    m_PropertyInfoMap["Point1"].setConnect();

    GY_PropertyInfo ctrl1(this);
    ctrl1.propertyName = "Ctrl1";
    ctrl1.propertyValue = QPointF(100,50);
    ctrl1.updateType = Update|PointOfRelative;
    ctrl1.propertyType = PointPropertyType;
    ctrl1.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsBezier::updateCtrl1;
    m_PropertyInfoMap.insert("Ctrl1",ctrl1);
    m_PropertyInfoMap["Ctrl1"].setConnect();

    GY_PropertyInfo ctrl2(this);
    ctrl2.propertyName = "Ctrl2";
    ctrl2.propertyValue = QPointF(120,80);
    ctrl2.updateType = Update|PointOfRelative;
    ctrl2.propertyType = PointPropertyType;
    ctrl2.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsBezier::updateCtrl2;
    m_PropertyInfoMap.insert("Ctrl2",ctrl2);
    m_PropertyInfoMap["Ctrl2"].setConnect();

    GY_PropertyInfo point2(this);
    point2.propertyName = "Point2";
    point2.propertyValue = QPointF(200,100);
    point2.updateType = Update|PointOfRelative;
    point2.propertyType = PointPropertyType;
    point2.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsBezier::updatePoint2;
    m_PropertyInfoMap.insert("Point2",point2);
    m_PropertyInfoMap["Point2"].setConnect();
}
